package Tree;
import Errors.ErrorLog;
import java.util.*;

/*******************************************************************************
 * Node of the tree.
 * @author Tudor Pascu
 * @version FINAL
 *******************************************************************************/
public abstract class Node
{
    static protected ErrorLog errorLog;//Used to log any errors from this class.
    private Node parent;
    private String token;
    private String type;
    private boolean explored;
    private ArrayList<Node> childNodes;

    /***************************************************************************
     * Creates a node having a token and a type.
     * @param token Token String.
     * @param type Token type.
     ***************************************************************************/
    public Node(String token, String type)
    {
        this.token = token;
        this.type = type;
        explored = false;
        childNodes = new ArrayList<Node>();
    }

    /***************************************************************************
     * Sets the ErrorLog of this object.
     * @param errors ErrorLog object.
     ***************************************************************************/
    static public void setErrorLog(ErrorLog errors)
    {
        errorLog = errors;
    }

    /***************************************************************************
     * Returns true if this node has a child, false otherwise.
     * @return True if this node has a child, false otherwise.
     ***************************************************************************/
    public boolean hasChild()
    {
        return childNodes.size() > 0;
    }

    /***************************************************************************
     * Sets the child node.
     * @param child Child node.
     ***************************************************************************/
    public void setChild(Node child)
    {
        childNodes.add(child);
        getChild().setParent(this);
    }

    /***************************************************************************
     * Returns the child node.
     * @return Child node.
     ***************************************************************************/
    public Node getChild()
    {
        int index = 0;
        for (int i = 0; i < childNodes.size(); i++)
        {
            if(!childNodes.get(i).isExplored())
            {
                index = i;
                i = childNodes.size(); //break;
            }
        }
        return getChild(index);
    }

    /***************************************************************************
     * Returns the child node of a particular node.
     * @param index The index value of a particular child.
     * @return A particular child node.
     ***************************************************************************/
    public Node getChild(int index)
    {
        if(hasChild())
        {
            return childNodes.get(index);
        }
        return null;
    }

    /***************************************************************************
     * Resets the explored value of a node.
     * @param node The node that has explored reset.
     ***************************************************************************/
    public static void resetExplored(Node node)
    {
        int index = 0;
        while(index < node.getChildren())
        {
            node.getChild(index).setExplored(false);
            if(node.getChild(index).hasChild()) resetExplored(node.getChild(index));
            index++;
        }
    }

    /***************************************************************************
     * Returns the number of children this node has.
     * @return Number of children this node has.
     ***************************************************************************/
    private int getChildren()
    {
        return childNodes.size();
    }

    /***************************************************************************
     * Sets the parent of this node.
     * @param parent Parent node of this node.
     ***************************************************************************/
    public void setParent(Node parent)
    {
        this.parent = parent;
    }

    /***************************************************************************
     * Returns the parent of this node.
     * @return Parent node.
     ***************************************************************************/
    public Node getParent()
    {
        return parent;
    }

    /***************************************************************************
     * Returns the type of the node.
     * @return Type of the node.
     ***************************************************************************/
    public String getType()
    {
        return type;
    }

    /***************************************************************************
     * Sets the type of this node.
     * @param type Type of the node.
     ***************************************************************************/
    public void setType(String type)
    {
        this.type = type;
    }

    /***************************************************************************
     * Returns the string of a token.
     * @return The token string.
     ***************************************************************************/
    public String getToken()
    {
        return token;
    }

    /***************************************************************************
     * Returns true if explored, false otherwise.
     * @return True if explored, false otherwise.
     ***************************************************************************/
    public boolean isExplored()
    {
        return explored;
    }

    /***************************************************************************
     * Sets explored to true if explored, false otherwise.
     * @param explored True if explored, false otherwise.
     ***************************************************************************/
    public void setExplored(boolean explored)
    {
        this.explored = explored;
    }
}